﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace TC.WEB.Site.Core
{
    /// <summary>
    /// 消息中心
    /// </summary>
    public class MessageCenter
    {
        /// <summary>
        /// datetime转换为unixtime
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static int ConvertDateTimeInt(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }

        public class QueueItem
        {
            /// <summary>
            /// 超时时间，分钟
            /// </summary>
            const int TIME_OUT = 2;

            internal int Id
            {
                get { return ConvertDateTimeInt(this.CreateTime); }
            }

            internal DateTime CreateTime { get; set; }

            internal bool IsTimeOut
            {
                get
                {
                    return CreateTime.AddMinutes(TIME_OUT) <= DateTime.Now;
                }
            }

            internal Message Message { get; set; }
        }

        public class QueueItem<T> : QueueItem where T : class
        {
            internal T Message { get; set; }
        }

        #region
        static MessageCenter _current;
        Queue<Message> _requestQueue;
        Dictionary<int, Queue<QueueItem>> _responseUserDataQueue;
        Dictionary<int, System.Threading.ManualResetEvent> _dicResetEvent;
        System.Threading.AutoResetEvent _mainResetEvent;
        static MessageCenter()
        {
            _current = new MessageCenter();
        }

        System.Timers.Timer _timer;
        System.ComponentModel.BackgroundWorker _bw1;
        System.ComponentModel.BackgroundWorker _bw2;
        private MessageCenter()
        {
            _requestQueue = new Queue<Message>();
            _responseUserDataQueue = new Dictionary<int, Queue<QueueItem>>();
            _mainResetEvent = new System.Threading.AutoResetEvent(false);
            _dicResetEvent = new Dictionary<int, System.Threading.ManualResetEvent>();

            _timer = new System.Timers.Timer();
            _timer.Interval = 1 * 1000;
            _timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);

            _bw1 = new System.ComponentModel.BackgroundWorker();
            _bw1.DoWork += new System.ComponentModel.DoWorkEventHandler(_bw1_DoWork);

            _bw2 = new System.ComponentModel.BackgroundWorker();
            _bw2.DoWork += new System.ComponentModel.DoWorkEventHandler(_bw2_DoWork);

            _timer.Start();
        }

        void _bw2_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            RemoveInvaidItem();
        }

        void _bw1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            Delivery();
        }

        void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            if (!_bw1.IsBusy)
            {
                _bw1.RunWorkerAsync();
            }
            if (!_bw2.IsBusy)
            {
                _bw2.RunWorkerAsync();
            }
        }
        #endregion

        /// <summary>
        /// 将数据分发至用户队列和数据处理队列
        /// </summary>
        private void Delivery()
        {
            List<Message> items = new List<Message>();
            lock (_requestQueue)
            {
                while (_requestQueue.Count > 0)
                {
                    if (items.Count >= 50) break;
                    items.Add(_requestQueue.Dequeue());
                }
            }
            if (items.Count <= 0)
            {
                _mainResetEvent.WaitOne(10 * 1000);
            }
            QueueItem qi;
            Queue<QueueItem> queue;
            items.ForEach(obj =>
            {
                if (!_responseUserDataQueue.ContainsKey(obj.ToUser))
                {
                    _responseUserDataQueue.Add(obj.ToUser, new Queue<QueueItem>());
                }
                queue = _responseUserDataQueue[obj.ToUser];
                qi = new QueueItem();
                qi.CreateTime = DateTime.Now;
                qi.Message = obj;
                queue.Enqueue(qi);
                GetEventByUserId(obj.ToUser).Set();
            });
            Delivery();
        }

        /// <summary>
        /// 移除已经超时的元素
        /// </summary>
        private void RemoveInvaidItem()
        {
            lock (_responseUserDataQueue)
            {
                foreach (var queue in _responseUserDataQueue)
                {
                    while (queue.Value.Count > 0 && queue.Value.Peek().IsTimeOut)
                    {
                        queue.Value.Dequeue();
                    }
                }
            }
            System.Threading.Thread.Sleep(10 * 1000);
            RemoveInvaidItem();
        }

        private System.Threading.ManualResetEvent GetEventByUserId(int user)
        {
            lock (_dicResetEvent)
            {
                if (!_dicResetEvent.ContainsKey(user))
                {
                    _dicResetEvent.Add(user, new System.Threading.ManualResetEvent(false));
                }
                return _dicResetEvent[user];
            }
        }

        public static MessageCenter Current { get { return _current; } }

        /// <summary>
        /// 添加站内消息
        /// </summary>
        /// <param name="msg"></param>
        public void Set(Message msg)
        {
            lock (_requestQueue)
            {
                _requestQueue.Enqueue(msg);
                _mainResetEvent.Set();
            }
        }

        /// <summary>
        /// 添加站内消息
        /// </summary>
        /// <param name="from">发送人</param>
        /// <param name="to">收件人</param>
        /// <param name="type">消息类型</param>
        /// <param name="title">消息标题</param>
        /// <param name="content">消息内容</param>
        public void Set(int from, int to, int type, string title, string content)
        {
            Set(new Message { FromUser = from, ToUser = to, Type = type, Title = title, Content = content});
        }

        /// <summary>
        /// 获取指定用户的最新消息
        /// </summary>
        /// <param name="last">最新消息ID</param>
        /// <param name="user">用户</param>
        /// <param name="rows">读取的消息条数</param>
        /// <param name="timeOut">超时时间（秒）</param>
        /// <returns></returns>
        public IEnumerable<QueueItem> Get(int last, int user, int rows, int timeOut)
        {
            Queue<QueueItem> queue = null;
            lock (_responseUserDataQueue)
            {
                if (_responseUserDataQueue.ContainsKey(user))
                {
                    queue = _responseUserDataQueue[user];
                }
            }
            if (queue == null || queue.Count == 0 || queue.Where(obj => obj.Id > last).Count() == 0)
            {
                System.Threading.ManualResetEvent manualResetEvent = GetEventByUserId(user);
                manualResetEvent.Reset();
                manualResetEvent.WaitOne(timeOut * 1000);
            }
            if (queue == null)
            {
                return new QueueItem[0];
            }
            List<QueueItem> items = new List<QueueItem>();
            //查询时不数据不再出列该防止多个请求获取信息时，某些请求无法获取数据的问题
            return queue.SkipWhile(obj => obj.Id <= last).Take(rows).ToArray();
        }
    }

    /// <summary>
    /// 站内消息
    /// </summary>
    public class Message
    {
        /// <summary>
        /// 发送人
        /// </summary>
        public int FromUser { get; set; }

        /// <summary>
        /// 收件人
        /// </summary>
        public int ToUser { get; set; }

        /// <summary>
        /// 消息类型
        /// </summary>
        [Obsolete]
        public int Type { get; set; }

        /// <summary>
        /// 消息标题
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// 消息内容
        /// </summary>
        public string Content { get; set; }
    }
}